package cn.iocoder.yudao.module.def.controller.admin.mysql.service;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.def.controller.admin.mysql.SystemMysqlBackupsMapper;
import cn.iocoder.yudao.module.def.controller.admin.mysql.vo.BackupsDO;
import cn.iocoder.yudao.module.def.controller.admin.mysql.vo.BackupsPageReqVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.util.Date;
import java.util.List;

/**
 * ClassName:SystemMysqlBackupsService
 * 类描述： MySQL备份实现
 */
@Slf4j
@Service
public class SystemMysqlBackupsServiceImpl extends ServiceImpl<SystemMysqlBackupsMapper, BackupsDO> implements SystemMysqlBackupsService {

    @Resource
    private SystemMysqlBackupsMapper systemMysqlBackupsMapper;

    @Override
    public List<BackupsDO> selectBackupsList() {
        return systemMysqlBackupsMapper.selectList(new LambdaQueryWrapper<>());
    }

    public String backupWithDynamicConfig(String filePath,  String userName,
                                        String password, String mysqlFileName, String ip, String port, String databaseName) {
        // 根据操作系统选择 mysqldump 路径
        String os = System.getProperty("os.name").toLowerCase();
        String mysqldumpPath = os.contains("win")
                ? "\"C:\\Program Files\\MySQL\\MySQL Server 8.4\\bin\\mysqldump.exe\""
                : "/usr/bin/mysqldump";

        // 动态构建命令
        String command = String.format(
                "%s --no-tablespaces -h%s -P%d -u%s -p\"%s\" --ignore-table %s.mysql_backups %s >%s",
                mysqldumpPath,
                ip,
                Integer.parseInt(port),
                userName,
                password,
                databaseName,
                databaseName,
                filePath+mysqlFileName
        );
        // 确保输出目录存在
        File outputDir = new File(filePath);
        if (!outputDir.exists()) {
            outputDir.mkdirs();
        }
        // 执行命令
        CommandLine cmdLine = CommandLine.parse("cmd.exe /c " + command);
        DefaultExecutor executor = new DefaultExecutor();
        try  {
//            executor.setStreamHandler(new PumpStreamHandler(fos));
            executor.execute(cmdLine);
            log.info("备份成功");
        } catch (Exception e) {
            log.error("备份失败", e);
        }
        return command;
    }
    @Override
    public Object mysqlBackups(String filePath, String url, String userName, String password) {

        // 获取ip
        final String ip = url.substring(13, 22);
        // 获取端口号
        final String port = url.substring(23, 27);
        // 获取数据库名称
        final String databaseName = url.substring(28, 41);
        // 数据库文件名称
        StringBuilder mysqlFileName = new StringBuilder()
                .append("backup")
                .append("_")
                .append(DateUtil.format(new Date(), "yyyy-MM-dd-HH-mm-ss"))
                .append(".sql");
        String cmd = backupWithDynamicConfig(filePath, userName, password, mysqlFileName.toString(), ip, port, databaseName);
        // 判断文件是否保存成功
        if (!FileUtil.exist(filePath)) {
            FileUtil.mkdir(filePath);

        }
        BackupsDO smb = new BackupsDO();
        // 备份信息存放到数据库
        smb.setMysqlIp(ip);
        smb.setMysqlPort(port);
        smb.setBackupsName(String.valueOf(mysqlFileName));
        smb.setDatabaseName(databaseName);
        smb.setMysqlCmd(String.valueOf(cmd));
        smb.setBackupsPath(filePath);
        smb.setCreateTime(DateTime.now());
        smb.setStatus(1);
        smb.setOperation(0);
        systemMysqlBackupsMapper.insert(smb);
        return smb;
    }
    public static boolean isSystem(String osName) {
        Boolean flag = null;
        if (osName.startsWith("windows")) {
            flag = true;
        } else if (osName.startsWith("linux")) {
            flag = false;
        }
        return flag;
    }

    @Override
    public BackupsDO selectListId(Long id) {
        return systemMysqlBackupsMapper.selectById(id);
    }


    public Object rollback1(BackupsDO smb, String userName, String password) {
        // 备份路径和文件名
        StringBuilder realFilePath = new StringBuilder().append(smb.getBackupsPath()).append(smb.getBackupsName());
        if (!FileUtil.exist(String.valueOf(realFilePath))) {
//            return new ErrorTip(HttpStatus.NOT_FOUND.value(), "文件不存在，恢复失败，请查看目录内文件是否存在后重新尝试！");
        }
        StringBuilder cmd = new StringBuilder()
                .append("mysql -h")
                .append(smb.getMysqlIp())
                .append(" -u")
                .append(userName)
                .append(" -p")
                .append(password)
                .append(" ")
                .append(smb.getDatabaseName())
                .append(" < ")
                .append(realFilePath);
        String[] command = new String[0];
        log.error("数据库恢复命令为：{}", cmd);
        // 获取操作系统名称
        String osName = System.getProperty("os.name").toLowerCase();
        if (isSystem(osName)) {
            // Windows
            command = new String[]{"cmd", "/c", String.valueOf(cmd)};
        } else {
            // Linux
            command = new String[]{"/bin/sh", "-c", String.valueOf(cmd)};
        }
        // 恢复指令写入到数据库
        smb.setMysqlBackCmd(String.valueOf(cmd));
        // 更新操作次数
        smb.setRecoveryTime(DateTime.now());
        smb.setOperation(smb.getOperation() + 1);
        // 获取Runtime实例
        Process process = null;
        try {
            process = Runtime.getRuntime().exec(command);
            if (process.waitFor() == 0) {
                log.error("Mysql 数据库恢复成功,恢复文件名：{}", realFilePath);
            } else {
//                return new ErrorTip(HttpStatus.GATEWAY_TIMEOUT.value(), "网络异常，恢复失败，请稍后重新尝试！");
            }
        } catch (Exception e) {
            e.printStackTrace();
//            return new ErrorTip(HttpStatus.GATEWAY_TIMEOUT.value(), "网络异常，恢复失败，请稍后重新尝试！");
        }
        return smb;
    }
    @Override
    public Object rollback(BackupsDO smb, String userName, String password) {
        // 备份路径和文件名
        StringBuilder realFilePath = new StringBuilder().append(smb.getBackupsPath()).append(smb.getBackupsName());
        if (!FileUtil.exist(String.valueOf(realFilePath))) {
            log.error("文件不存在，恢复失败，请查看目录内文件是否存在后重新尝试！");
            return smb; // 或者抛出异常
        }

        // 根据操作系统选择 mysql 路径
        String os = System.getProperty("os.name").toLowerCase();
        String mysqlPath = os.contains("win")
                ? "\"C:\\Program Files\\MySQL\\MySQL Server 8.4\\bin\\mysql.exe\""
                : "/usr/bin/mysql";

        // 动态构建命令
        String command = String.format(
                "%s -h%s -P%d -u%s -p\"%s\" %s <%s",
                mysqlPath,
                smb.getMysqlIp(),
                Integer.parseInt(smb.getMysqlPort()),
                userName,
                password,
                smb.getDatabaseName(),
                realFilePath
        );

        // 执行命令
        CommandLine cmdLine = CommandLine.parse("cmd.exe /c " + command);
        DefaultExecutor executor = new DefaultExecutor();
        try {
            executor.execute(cmdLine);
            log.info("Mysql 数据库恢复成功,恢复文件名：{}", realFilePath);
            // 更新操作次数
            smb.setRecoveryTime(DateTime.now());
            smb.setOperation(smb.getOperation() + 1);
            smb.setMysqlBackCmd(String.valueOf(command));
            smb.setStatus(2); // 假设2表示恢复成功
            systemMysqlBackupsMapper.updateById(smb);
        } catch (Exception e) {
            log.error("Mysql 数据库恢复失败", e);
            smb.setStatus(3); // 假设3表示恢复失败
            systemMysqlBackupsMapper.updateById(smb);
        }
        return smb;
    }

    @Override
    public PageResult<BackupsDO> getBackupsPage(BackupsPageReqVO backupsPageReqVO) {
        return systemMysqlBackupsMapper.selectPage(backupsPageReqVO);

    }
}
